package edu.kit.aifb.bowsim.index;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.analysis.de.GermanAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import org.semanticweb.yars.nx.DateTimeLiteral;
import org.semanticweb.yars.nx.Literal;
import org.semanticweb.yars.nx.Node;
import org.semanticweb.yars.nx.NumericLiteral;
import org.semanticweb.yars.nx.Resource;

public class TextIndexWriter {
	transient Logger _log = Logger.getLogger(this.getClass().getName());

	public static final String URI = "uri";
//	public static final String TITLE = "title";
//	public static final String DESCRIPTION = "description";
//	public static final String DATE = "date";
//	public static final String ENTITY = "entity";
	
	public static final String[] STOP_WORDS = { "a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your" };
	
	IndexWriter _writer;
	
	public TextIndexWriter(File dir, String analyser, boolean create) throws CorruptIndexException, LockObtainFailedException, IOException {
		if (dir.exists() && dir.isDirectory() && create) {
			delete(dir);
		}

		Directory ldir = new SimpleFSDirectory(dir);
		
		Analyzer an = null;
		
		if ("de".equals(analyser)) {
			an = new GermanAnalyzer(Version.LUCENE_30);
			_log.info("using de analyser");
		} else if ("cjk".equals(analyser)) {
			an = new CJKAnalyzer(Version.LUCENE_30);
			_log.info("using cjk analyser");
		} else {
			an = new StandardAnalyzer(Version.LUCENE_30, new HashSet<String>(Arrays.asList(STOP_WORDS)));
			_log.info("using en analyser");
		}
		
		_writer = new IndexWriter(ldir, an, IndexWriter.MaxFieldLength.LIMITED);
	}
	
	public void addAll(Iterator<Node[]> quads) throws CorruptIndexException, IOException {
		Node oldSub = null;
		Node subject = null;
		Set<Node[]> predobjs = new HashSet<Node[]>();
		
		while (quads.hasNext()) {
			Node[] nx = quads.next();

			subject = nx[0];

			if ((oldSub != null) && (!subject.equals(oldSub))) {
				if (!predobjs.isEmpty()) {
					add(oldSub, predobjs);
				}

				predobjs = new HashSet<Node[]>();
			}

			Node[] po = new Node[2];
			po[0] = nx[1];
			po[1] = nx[2];
			
			predobjs.add(po);

			oldSub = subject;
		}

		if (!predobjs.isEmpty()) {
			add(oldSub, predobjs);
		}
	}

	public void add(Node subj, Set<Node[]> predobjs) throws CorruptIndexException, IOException {
		Document doc = new Document();

		doc.add(new Field(URI, subj.toN3(), Field.Store.YES, Field.Index.NOT_ANALYZED));

		for (Node[] po : predobjs) {
			Node p = po[0];
			Node o = po[1];
			
			if (o instanceof DateTimeLiteral) {
				_log.fine("date");
			} else if (o instanceof NumericLiteral) {
				_log.fine("number");
			} else if (o instanceof Literal) {
				//doc.add(new Field("TEXT", o.toString(), Field.Store.YES, Field.Index.ANALYZED, TermVector.YES));							
				doc.add(new Field(p.toN3(), o.toString(), Field.Store.YES, Field.Index.ANALYZED, TermVector.YES));
				_log.info(p.toN3() + ": " + o.toString());
			} else if (o instanceof Resource) {
				doc.add(new Field(p.toN3(), o.toN3(), Field.Store.YES, Field.Index.NOT_ANALYZED, TermVector.YES));
			}
		}
		
		_log.info("adding document " + doc);
		
		_writer.addDocument(doc);
	}
	
	public IndexWriter getIndexWriter() {
		return _writer;
	}
	
	public void close() throws CorruptIndexException, IOException {
		_writer.commit();
		_writer.optimize();
		_writer.close();
	}

	public static void delete(File dir) throws IOException {
        String[] children = dir.list();
        if (children != null) {
        	for (String file : children) {
        		File f = new File(dir, file);
        		delete(f);
        	}
        }
        if (!dir.delete()) {
        	throw new IOException("couldn't delete file" +  dir); 	
        }
    }
}
